package cn.com.lyj6851.modules.auth.controller;

import cn.com.lyj6851.api.ApiResult;
import cn.com.lyj6851.api.MyShopException;
import cn.com.lyj6851.common.enums.SmsTypeEnum;
import cn.com.lyj6851.common.util.JwtToken;
import cn.com.lyj6851.common.util.SmsUtils;
import cn.com.lyj6851.constant.ShopConstants;
import cn.com.lyj6851.enums.ShopCommonEnum;
import cn.com.lyj6851.modules.auth.param.HLoginParam;
import cn.com.lyj6851.modules.auth.param.LoginParam;
import cn.com.lyj6851.modules.auth.param.RegParam;
import cn.com.lyj6851.modules.auth.param.VerityParam;
import cn.com.lyj6851.modules.service.AuthService;
import cn.com.lyj6851.modules.user.domain.YdyUser;
import cn.com.lyj6851.modules.user.service.YdyUserService;
import cn.com.lyj6851.utils.RedisUtils;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.exceptions.ClientException;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * App认证服务
 */
@Slf4j
@RestController
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@Api(value = "认证模块", tags = "商城:认证", description = "认证")
public class AppAuthController {

    private final YdyUserService userService;
    private final RedisUtils redisUtil;
    private final AuthService authService;


    @Value("${single.login}")
    private Boolean singleLogin;//是否限制单用户登录

    /**
     * 小程序登陆接口
     */
    @PostMapping("/wxapp/auth")
    @ApiOperation(value = "小程序登陆", notes = "小程序登陆")
    public ApiResult<Map<String, Object>> login(@Validated @RequestBody LoginParam loginParam,
                                                HttpServletRequest request) {
        YdyUser ydyUser = authService.wxappLogin(loginParam);
        // 生成token
        String token = JwtToken.makeToken(ydyUser.getUid());
        String expiresTimeStr = JwtToken.getExpireTime(token);
        // 返回 token
        Map<String, Object> map = new LinkedHashMap<>(2);

        map.put("token", token);
        map.put("expires_time", expiresTimeStr);
        // 保存在线信息
        authService.save(ydyUser, token, request);
        if(singleLogin){//如果限制单用户登录
            authService.checkLoginOnUser(ydyUser.getUsername(),token);
        }

        return ApiResult.ok(map).setMsg("登陆成功");
    }

    /**
     * 微信公众号授权
     */
    @GetMapping("/wechat/auth")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "code", value = "微信授权code", paramType = "query", dataType = "string"),
            @ApiImplicitParam(name = "spread", value = "分销绑定关系的ID", paramType = "query", dataType = "string")
    })
    @ApiOperation(value = "微信公众号授权", notes = "微信公众号授权")
    public ApiResult<Map<String, Object>> authLogin(@RequestParam(value = "code") String code,
                                                    @RequestParam(value = "spread") String spread,
                                                    HttpServletRequest request) {
        //根据code和分销码获取登录信息
        YdyUser ydyUser = authService.wechatLogin(code,spread);
        String token = JwtToken.makeToken(ydyUser.getUid());
        String expiresTimeStr = JwtToken.getExpireTime(token);

        Map<String,Object> map = new HashMap<String,Object>(2){
            private static final long serialVersionUID = 8156484841514197929L;
            {
            put("token",token);
            put("expires_time",expiresTimeStr);
        }};
        //保存在线状态
        authService.save(ydyUser,token,request);
        if(singleLogin){//如果限制单用户登录
            authService.checkLoginOnUser(ydyUser.getUsername(),token);
        }
        return ApiResult.ok(map).setMsg("登录成功");
    }

    @ApiOperation("H5登录授权")
    @PostMapping(value = "/login")
    public ApiResult<Map<String, Object>> login(@Validated @RequestBody HLoginParam loginDTO, HttpServletRequest request) {
        //通过用户名密码获取用户信息
        final YdyUser ydyUser = userService.getOne(Wrappers.<YdyUser>lambdaQuery()
                .eq(YdyUser::getPhone, loginDTO.getAccount())
                .eq(YdyUser::getPassword, SecureUtil.md5(loginDTO.getPassword())));

        if(ydyUser == null){
            throw new MyShopException("账号或密码不正确");
        }
        String token = JwtToken.makeToken(ydyUser.getUid());
        String expiresTimeStr = JwtToken.getExpireTime(token);
        //保存在线状态
        authService.save(ydyUser,token,request);
        // 返回 token
        Map<String,Object> map = new HashMap<String,Object>(2){
            private static final long serialVersionUID = -621440047583115290L;
            {
            put("token",token);
            put("expires_time",expiresTimeStr);
        }};

        //设置分销上下级(上级id,自已的id)
        userService.setSpread(loginDTO.getSpread(),ydyUser.getUid());
        if(singleLogin){
            //踢掉之前已经登录的token
            authService.checkLoginOnUser(ydyUser.getUsername(),token);
        }
        return ApiResult.ok(map).setMsg("登录成功");
    }

    @PostMapping("/register")
    @ApiOperation(value = "H5/APP注册新用户", notes = "H5/APP注册新用户")
    public ApiResult<String> register(@Validated @RequestBody RegParam param) {
        Object codeObj = redisUtil.get("code_" + param.getAccount());
        if(codeObj == null){
            return ApiResult.fail("请先获取验证码");
        }
        String code = codeObj.toString();
        if (!StrUtil.equals(code, param.getCaptcha())) {
            return ApiResult.fail("验证码错误");
        }
        YdyUser ydyUser = userService.getOne(Wrappers.<YdyUser>lambdaQuery()
                      .eq(YdyUser::getPhone,param.getAccount()),false);
        if(ObjectUtil.isNotNull(ydyUser)){
            return ApiResult.fail("用户已经存在");
        }
        authService.register(param);
        return ApiResult.ok("","注册成功");
    }

    @PostMapping("/register/verify")
    @ApiOperation(value = "短信验证码发送", notes = "短信验证码发送")
    public ApiResult<String> verify(@Validated @RequestBody VerityParam param) {
        YdyUser ydyUser = userService.getOne(Wrappers.<YdyUser>lambdaQuery()
                        .eq(YdyUser::getPhone,param.getPhone()),false);

        if(SmsTypeEnum.REGISTER.getValue().equals(param.getType())&&ObjectUtil.isNotNull(ydyUser)){
            return ApiResult.fail("手机号已注册");
        }
        if(SmsTypeEnum.LOGIN.getValue().equals(param.getType())&&ObjectUtil.isNull(ydyUser)){
            return ApiResult.fail("帐号不存在");
        }
        String codeKey = "code_" + param.getPhone();
        if(ObjectUtil.isNotNull(redisUtil.get(codeKey))){// 如果缓存中验证码不为空
            return ApiResult.fail("10分钟内有效:" + redisUtil.get(codeKey).toString());
        }
        // 生成指定位的验证码
        String code = RandomUtil.randomNumbers(ShopConstants.LYJ_SHOP_SMS_SIZE);
        // 存储
        redisUtil.set(codeKey,code,ShopConstants.LYJ_SHOP_SMS_REDIS_TIME);

        // 判断短信验证是否开启
        String enable = redisUtil.getY("sms_enable");
        if (ShopCommonEnum.ENABLE_2.getValue().toString().equals(enable)) {//如果是关闭状态
            return ApiResult.fail("测试阶段验证码:" + code);
        }

        //发送阿里云短信
        JSONObject json = new JSONObject();
        json.put("code",code);
        try {
            SmsUtils.sendSms(param.getPhone(),json.toJSONString());
        } catch (ClientException e) {
            redisUtil.del(codeKey);
            e.printStackTrace();
            return ApiResult.ok("发送失败："+e.getErrMsg());
        }
        return ApiResult.ok("发送成功，请注意查收");
    }


    @ApiOperation(value = "退出登录", notes = "退出登录")
    @PostMapping(value = "/auth/logout")
    public ApiResult<String> logout(HttpServletRequest request) {
        String bearerToken = request.getHeader("Authorization");
        String[] tokens = bearerToken.split(" ");
        String token = tokens[1];
        authService.logout(token);
        return ApiResult.ok("退出成功");
    }

}
